package cn.edu.zut.score.service.biz;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author zby
 * @date 2021/08/04
 */
@ApiModel("websocket服务类")
@ServerEndpoint(value = "/message/{userId}")
@Component
@EqualsAndHashCode
@Slf4j
public class WebSocketService {
    @ApiModelProperty("静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。")
    private static int onlineCount = 0;

    @ApiModelProperty("concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。")
    private static final CopyOnWriteArraySet<WebSocketService> WEB_SOCKET_SET = new CopyOnWriteArraySet<>();

    @ApiModelProperty("与某个客户端的连接会话，需要通过它来给客户端发送数据")
    private Session session;

    @ApiModelProperty("某个客户端的连接对应的用户ID，需要用它选择性发送数据")
    private Long userId;

    @ApiOperation("连接成功调用的方法")
    @OnOpen
    public void onOpen(@PathParam("userId") Long userId, Session session) {
        this.session = session;
        this.userId = userId;
        //加入到Set中
        WEB_SOCKET_SET.add(this);
        //在线人数加一
        addOnlineCount();
        log.info("有新用户ID为：{}的连接加入，当前在线人数为：{}", userId, getOnlineCount());
    }

    @ApiOperation("连接关闭调用的方法")
    @OnClose
    public void onClose() {
        log.info("用户ID为：{}的连接关闭，当前在线人数为：{}", this.userId, getOnlineCount());
        //从Set中删除
        WEB_SOCKET_SET.remove(this);
        //在线人数减一
        subOnlineCount();
    }

    @ApiOperation("收到客户端消息后调用的方法")
    @OnMessage
    public void onMessage(String message) {
        log.info("来自用户ID为：{}的用户的消息：{}", userId, message);
        //此处可以调用自定义发送消息方法，本系统暂时用不到
    }

    @ApiOperation("发生错误时调用的方法")
    @OnError
    public void onError(Throwable error) {
        log.error("发生错误", error);
    }

    @ApiOperation("发送评分消息给指定的用户")
    public void sendAssignMessage(String studentName, Map<Long, Long> map) {
        for (Map.Entry<Long, Long> entry : map.entrySet()) {
            Long messageId = entry.getKey();
            Long to = entry.getValue();
            String message = "{\"id\":" + messageId.toString() + ",\"name\":\"" + studentName + "\"}";
            log.info("待发送的消息（JSON格式）为：{}", message);
            for (WebSocketService webSocketService : WEB_SOCKET_SET) {
                if (to.equals(webSocketService.userId)) {
                    try {
                        webSocketService.session.getBasicRemote().sendText(message);
                    } catch (IOException e) {
                        log.error("发送消息给用户{}时出错！", webSocketService.userId, e);
                    }
                }
            }
        }
    }

    @ApiOperation("发送答辩学生信息消息给指定用户")
    public void sendInfoMessage(String clazzName, String studentName, List<Long> receiveIds) {
        String message = "当前答辩的学生为<strong>" + clazzName + "</strong>的<strong>" + studentName + "</strong>，请准备在其答辩结束后为其评分。";
        log.info("待发送的消息为：{}", message);
        for (WebSocketService webSocketService : WEB_SOCKET_SET) {
            if (receiveIds.contains(webSocketService.userId)) {
                try {
                    webSocketService.session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.error("发送消息给用户{}时出错！", webSocketService.userId, e);
                }
            }
        }
    }

    @ApiOperation("发送提醒信息消息给指定用户")
    public void sendOtherMessage(List<Long> receiveIds) {
        String message = "提醒";
        log.info("待发送的消息为：{}", message);
        for (WebSocketService webSocketService : WEB_SOCKET_SET) {
            if (receiveIds.contains(webSocketService.userId)) {
                try {
                    webSocketService.session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.error("发送消息给用户{}时出错！", webSocketService.userId, e);
                }
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketService.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketService.onlineCount--;
    }
}
